#include <iostream>
#include <unistd.h>
#include <chrono>
#include <time.h>
#include <poll.h>

#include <gtest/gtest.h>
#include <libgo/coroutine.h>
#include "gtest_exit.h"
using namespace co;

#define O(x) std::cout << x << std::endl

namespace async {

AsyncCoroutinePool* gPool = AsyncCoroutinePool::Create();

struct R {
    R() = default;
    explicit R(int v) : val_(v) {}

#ifndef WIN32
    R(R&&) = default;
    R& operator=(R&&) = default;
#endif

    R(R const&) {
        O("R copyed.");
    }

#ifndef WIN32
    R& operator=(R const&) = delete;
#endif

    int val_;
};

R calc() {
    return R(8);
}

void cb1(R val) {
    O("callback by value, val = " << val.val_);
}

void cb2(R& val) {
    O("callback by reference, val = " << val.val_);
}
}

TEST(AsyncPool, test) {
    using namespace async;

    gPool->InitCoroutinePool(128);
    gPool->Start(4, 12);

    std::atomic<int> val{0};

    AsyncCoroutinePool::CallbackPoint* cbPoint = new AsyncCoroutinePool::CallbackPoint;
    cbPoint->SetNotifyFunc([&] {
        ++val;
    });
    gPool->AddCallbackPoint(cbPoint);

    gPool->Post<R>(&calc, &cb1);
    gPool->Post<R>(&calc, &cb2);

    uint64_t threadId = NativeThreadID();
    const int c = 100;

    for (int i = 0; i < c; ++i)
        gPool->Post([&] {
        ++val;
        O("run task");
    }, [&] {
        ++val;
        EXPECT_EQ(threadId, NativeThreadID());
        O("run callback");
    });

    while (val != c * 3 + 2) {
        cbPoint->Run();
    }
}
